package com.cbtx.module.base.http;

import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Display;

import com.cbtx.module.base.ContextManager;
import com.cbtx.module.base.SignUtil;
import com.cbtx.module.base.TokenUtil;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.txcb.lib.base.utils.LogUtil;
import com.txcb.lib.base.utils.SharedPreferencesUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
//import rx.Observable;
//import rx.Subscriber;
//import rx.android.schedulers.AndroidSchedulers;
//import rx.schedulers.Schedulers;


/**
 * Created by XYSM on 2017/6/11.
 */

@SuppressLint("NewApi")
public class HttpManager {


    public static final MediaType FORM_CONTENT_TYPE =
            MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");

    public final static String POST = "POST";
    public final static String PATCH = "PATCH";
    public final static String GET = "GET";
    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
    private static HttpManager sInstance;
    /**
     * post方式请求
     *
     * @param url       请求连接地址
     * @param param     请求参数
     * @param callBacks 上传回调
     */

    public boolean isHttpCommonAuth = false;
    private OkHttpClient mOkHttpClient;

    private HttpManager(Interceptor interceptor) {
        mOkHttpClient = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .addInterceptor(chain -> {
                    Request request = chain.request();

                    FormBody.Builder builder = new FormBody.Builder();
                    if (request.body() instanceof FormBody) {
                        // 构造新的请求表单
                        FormBody body = (FormBody) request.body();
                        // 将原来的参数放入新的表单中
                        for (int i = 0; i < body.size(); i++) {
                            builder.addEncoded(body.encodedName(i), body.encodedValue(i));
                        }
                    }

                    // 添加公共参数
                    long currentTime = System.currentTimeMillis();
                    builder.addEncoded("timestamp", "" + currentTime);
                    Request.Builder reqBuild = request.newBuilder();
                    //分辨率 not null
                    reqBuild.addHeader("resolution", getResolutions(1));
                    reqBuild.addHeader("token", TokenUtil.getToken()); //令牌，注册并初始化后的身份标识
                    reqBuild.addHeader("sign", SignUtil.getSign(request, currentTime));
                    request = reqBuild.post(builder.build()).build(); //构造新的请求体
                    return chain.proceed(request);
                })
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request()
                                .newBuilder()
                                .addHeader("authorization", sAuthorization)
                                .build();
                        return chain.proceed(request);
                    }
                })
//                .cookieJar(new CookieManger(UI.getContext()))
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

    }

    public String getResolutions(int screenNum) {
        Display[] displays = getDisplays();
        String resolutions = "";
        //需求方要求单屏机返回1个分辨率，其他屏幕返回系统取出来的个数
        switch (screenNum) {
            case 1:
                for (Display display : displays) {
                    if (display.getDisplayId() == 0) {
                        resolutions = getDisplayWidth(display) + "x" + getDisplayHeight(display);
                    }
                }
                break;
            default:
                for (Display display : displays) {
                    resolutions += getDisplayWidth(display) + "x" + getDisplayHeight(display) + ",";
                }
                resolutions = TextUtils.isEmpty(resolutions) ? "" : resolutions.substring(0, resolutions.length() - 1);
        }
        if (TextUtils.isEmpty(resolutions)) {
            resolutions = "1920x1080";
        }
        return resolutions;
    }

    public int getDisplayWidth(Display display) {
        DisplayMetrics metrics = getDisPlayMetrics(display);
        if (metrics == null) {
            return 0;
        }
        return metrics.widthPixels;
    }

    public int getDisplayHeight(Display display) {
        DisplayMetrics metrics = getDisPlayMetrics(display);
        if (metrics == null) {
            return 0;
        }
        return metrics.heightPixels;
    }

    private DisplayMetrics getDisPlayMetrics(Display display) {
        DisplayMetrics metrics = new DisplayMetrics();
        display.getRealMetrics(metrics);
        return metrics;
    }

    public Display[] getDisplays() {
        DisplayManager mDisplayManager = (DisplayManager) ContextManager.INSTANCE.getContext()
                .getSystemService(Context.DISPLAY_SERVICE);
        return mDisplayManager.getDisplays();
    }


    public static String sAuthorization = "";

    public static void setAuthorization(String authorization) {
        sAuthorization = authorization;
    }


    public static HttpManager getInstance(String authorization, Interceptor interceptor) {

        if (!TextUtils.isEmpty(authorization)) {
            sAuthorization = authorization;
        }

        LogUtil.d("authorization:" + sAuthorization);

        if (sInstance == null) {
            synchronized (HttpManager.class) {
                if (sInstance == null) {
                    sInstance = new HttpManager(interceptor);
                }
            }
        }
        return sInstance;
    }

    public static HttpManager getsInstance() {

        sAuthorization = SharedPreferencesUtils.loadString("authorization");
        LogUtil.d("authorization:" + sAuthorization);

        if (sInstance == null) {
            synchronized (HttpManager.class) {
                if (sInstance == null) {
                    sInstance = new HttpManager(null);

                }
            }
        }
        return sInstance;
    }

    /**
     * 表单提交
     *
     * @param url       请求连接地址
     * @param param     请求参数
     * @param picKey    上传的文件参数
     * @param fileList  上传的文件
     * @param callBacks 上传回调
     */

    public void sendForm(final String url, final Map<String, String> param, final String picKey,
                         final List<File> fileList, final MyRequestCallBack callBacks) {
        sendMultipart(url, param, picKey, fileList)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Observer<String>() {

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onComplete() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        if (callBacks != null) {
                            callBacks.onFailure(-201, "网络加载失败");
                        }
                    }


                    @Override
                    public void onNext(String json) {

                        String jsons = json;

                        try {
                            Object object = GsonUtil.jsonToBean(json, callBacks.getClazz());
                            callBacks.onSuccess(object);

                        } catch (JsonSyntaxException e) {
                            if (callBacks != null) {
                                callBacks.onFailure(-201, "数据无效");
                            }
                        }
                    }
                });
    }

    public Observable<String> sendMultipart(final String reqUrl, final Map<String, String> params,
                                            final String picKey, final List<File> files) {
        return Observable.create(new ObservableOnSubscribe<String>() {

            @Override
            public void subscribe(final ObservableEmitter<String> emitter) throws Exception {
                MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
                multipartBodyBuilder.setType(MultipartBody.FORM);

                //遍历paths中所有图片绝对路径到builder，并约定key如“upload”作为后台接受多张图片的key
                if (files != null) {
                    for (File file : files) {
                        multipartBodyBuilder.addFormDataPart(picKey, file.getName(),
                                RequestBody.create(MEDIA_TYPE_PNG, file));
                    }
                }

                //遍历map中所有参数到builder
                if (params != null) {
                    for (String key : params.keySet()) {
                        multipartBodyBuilder.addFormDataPart(key, params.get(key));
                    }
                }

                //构建请求体
                RequestBody requestBody = multipartBodyBuilder.build();

                Request.Builder RequestBuilder = new Request.Builder();
                RequestBuilder.url(reqUrl); // 添加URL地址
                RequestBuilder.post(requestBody);
                Request request = RequestBuilder.build();

                mOkHttpClient.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        emitter.onError(e);
//                        emitter.onCompleted();
                        call.cancel();
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        String str = response.body().string();
                        emitter.onNext(str);
//                        emitter.onCompleted();
                        call.cancel();
                    }
                });
            }
        });
    }

    /**
     * post方式请求
     *
     * @param url       请求连接地址
     * @param param     请求参数
     * @param callBacks 上传回调
     */
    public void sendPost(final String url, Map<String, Object> param, final MyRequestCallBack callBacks) {
//        LogUtils.d("sendPostToken:" + token + "\nurl:" + url);
        send(POST, url, param)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<String>() {

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String json) {
                        LogUtil.d("url" + url);

                        // LogUtils.d("json" + json);
                        parseJson(json, callBacks);
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (callBacks != null) {
                            callBacks.onFailure(-100, "网络加载失败");
                        }
                    }

                    @Override
                    public void onComplete() {

                    }


                });
    }


    /**
     * get 方式请求
     *
     * @param url       请求连接地址
     * @param param     请求参数
     * @param callBacks 上传回调
     */
    public void sendGet(final String url, Map<String, Object> param, final MyRequestCallBack callBacks) {


        send(GET, url, param)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onComplete() {

                    }

                    @Override
                    public void onError(Throwable e) {

                        LogUtil.e("Throwable:" + e);
                        if (callBacks != null) {
                            callBacks.onFailure(-100, "网络加载失败");
                        }

                    }

                    @Override
                    public void onNext(String json) {
                        LogUtil.d("result:" + url + ":" + json);

                        parseJson(json, callBacks);
                    }
                });
    }


    /**
     * get 方式请求
     *
     * @param url       请求连接地址
     * @param param     请求参数
     * @param callBacks 上传回调
     */
    public void sendPatch(final String url, Map<String, Object> param, final MyRequestCallBack callBacks) {

        send(PATCH, url, param)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onComplete() {

                    }

                    @Override
                    public void onError(Throwable e) {

                        LogUtil.e("Throwable:" + e);
                        if (callBacks != null) {
                            callBacks.onFailure(-100, "网络加载失败");
                        }

                    }

                    @Override
                    public void onNext(String json) {
                        LogUtil.d("result:" + url + ":" + json);

                        parseJson(json, callBacks);
                    }
                });
    }


    public Observable<String> send(final String requestType, final String reqUrl, final Map<String, Object> params) {


        return Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(final ObservableEmitter<String> emitter) throws Exception {
                Request.Builder requestBuilder = new Request.Builder();

                //判断post/get 请求方式
                if (PATCH.equals(requestType)) {

                    RequestBody requestBody = setRequestBody(params);
                    requestBuilder.url(reqUrl).method("PATCH", requestBody).build();

                } else if (POST.equals(requestType)) {
                    FormBody.Builder builder = new FormBody.Builder();
                    if (params != null) {
                        for (String key : params.keySet()) {
                            builder.add(key, params.get(key).toString());
                        }
                    }

                    requestBuilder.url(reqUrl);
                    requestBuilder.post(builder.build());
                } else {
                    requestBuilder.url(reqUrl + setUrlParams(params));
                    requestBuilder.get();
                }

                LogUtil.e("http Url :" + (reqUrl + setUrlParams(params)));
                mOkHttpClient.newCall(requestBuilder.build()).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        LogUtil.d("IOException:" + e);
                        emitter.onError(e);
//                        subscriber.onCompleted();
                        call.cancel();
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {

//                        LogUtil.d("response:"+response);
                        String str = response.body().string();
                        if (TextUtils.isEmpty(str) && response.code() == 200) {

                            HttpBaseBean httpBaseBean = new HttpBaseBean();
                            httpBaseBean.status = 200;

                            str = new Gson().toJson(httpBaseBean);
                        }
                        emitter.onNext(str);

//                        emitter.onCompleted();
                        call.cancel();
                    }
                });
            }
//            @Override
//            public void subscribe(final Subscriber<? super String> subscriber) {

//            }
        });
    }


    public void sendPostJson(final String url, String json, final MyRequestCallBack callBacks) {

        //获取缓存下来的token
//        String token = "";
//        LogUtils.d("sendGet：\nToken:" + token + "\nurl:" + url);

        postJson(url, json)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onComplete() {
                    }

                    @Override
                    public void onError(Throwable e) {

                        LogUtil.e("Throwable:" + e);
                        if (callBacks != null) {
                            callBacks.onFailure(-100, "网络加载失败");
                        }
                    }

                    @Override
                    public void onNext(String json) {
                        LogUtil.d("result:" + url + ":" + json);

                        parseJson(json, callBacks);
                    }
                });
    }

    private Observable<String> postJson(final String reqUrl, final String json) {


        return Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(final ObservableEmitter<String> emitter) throws Exception {
                Request.Builder requestBuilder = new Request.Builder();

                MediaType JSON_FORM = MediaType.parse("application/json; charset=utf-8");

                RequestBody requestBody = RequestBody.create(JSON_FORM, json);
                requestBuilder.url(reqUrl);
                requestBuilder.post(requestBody);

                mOkHttpClient.newCall(requestBuilder.build()).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        LogUtil.d("IOException:" + e);
                        emitter.onError(e);
//                        subscriber.onCompleted();
                        call.cancel();
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {

                        LogUtil.d("Response:" + response.code());
                        String str = response.body().string();
                        if (TextUtils.isEmpty(str) && response.code() == 200) {

                            HttpBaseBean httpBaseBean = new HttpBaseBean();
                            httpBaseBean.status = 200;

                            str = new Gson().toJson(httpBaseBean);
                        }

                        emitter.onNext(str);
//                        emitter.onCompleted();
                        call.cancel();
                    }
                });
            }

        });
    }


    private void parseJson(final String json, final MyRequestCallBack callBacks) {

        try {
            JsonParser parser = new JsonParser();
            JsonElement element = parser.parse(json);
            JsonObject root = element.getAsJsonObject();
            LogUtil.d("----------------json--------------------\n" + root.toString());
            // 解析一个节点


            Object object = GsonUtil.jsonToBean(json, callBacks.getClazz());
            callBacks.onSuccess(object);


//            Object object = GsonUtil.jsonToBean(json, callBacks.getClazz());
//            callBacks.onSuccess(object);
        } catch (Exception e) {
            LogUtil.d("----------------json error--------------------\n" + json);
            LogUtil.d("----------------Exception: --------------------\n" + e.toString());
            if (callBacks != null) {
                callBacks.onFailure(-201, "数据无效");
            }
        }
    }

    /**
     * post请求参数
     *
     * @param mapParams
     * @return
     */
    private RequestBody setRequestBody(Map<String, Object> mapParams) {


        StringBuffer stringBuffer = new StringBuffer();

        if (mapParams != null) {
            for (String key : mapParams.keySet()) {
                stringBuffer.append(key).append("=").append(mapParams.get(key)).append("&");
            }

            if (stringBuffer.length() > 1) {
                stringBuffer.deleteCharAt(stringBuffer.length() - 1);
            }
        }
        RequestBody body = RequestBody.create(FORM_CONTENT_TYPE, stringBuffer.toString());
        return body;

    }

    /**
     * get方法连接拼加参数
     *
     * @param mapParams
     * @return
     */
    private String setUrlParams(Map<String, Object> mapParams) {
//        String strParams = "1=1";
//        if (mapParams != null) {
//            for (String key : mapParams.keySet()) {
//                strParams += "&" + key + "=" + mapParams.get(key);
//            }
//        }
//        return strParams;

        StringBuffer strParams = new StringBuffer();
        if (mapParams != null) {
            strParams.append("?");
            for (String key : mapParams.keySet()) {
                strParams.append(key)
                        .append("=")
                        .append(mapParams.get(key))
                        .append("&");
//                strParams += "&" + key + "=" + mapParams.get(key);
            }

            strParams.deleteCharAt(strParams.length() - 1);
        }
        return strParams.toString();
    }

    public void downloadFile(final String url, final String savePath, final String saveFileName,
                             final OnDownloadListener onDownloadListener) {
        download(url, savePath, saveFileName)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onComplete() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        //下载失败
                        onDownloadListener.onDownloadFailed();
                    }

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer progress) {
                        //下载返回的进度
                        if (progress >= 100) {
                            //下载完成
                            onDownloadListener.onDownloadSuccess(savePath);
                        } else {
                            //下载中
                            onDownloadListener.onDownloading(progress);
                        }
                    }
                });
    }

    public Observable<Integer> download(final String url, final String savePath, final String saveFileName) {
        return Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(final ObservableEmitter<Integer> emitter) throws Exception {
                Request request = new Request.Builder().url(url).build();
                mOkHttpClient.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        emitter.onError(e);
                        call.cancel();
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        InputStream is = null;
                        byte[] buf = new byte[2048];
                        int len = 0;
                        FileOutputStream fos = null;
                        //储存下载文件的目录

                        try {
                            is = response.body().byteStream();
                            long total = response.body().contentLength();
                            File file = new File(savePath, saveFileName);
                            fos = new FileOutputStream(file);
                            long sum = 0;

                            int oldProgress = 0;
                            while ((len = is.read(buf)) != -1) {
                                fos.write(buf, 0, len);
                                sum += len;
                                int progress = (int) (sum * 1.0f / total * 100);
                                //下载中
                                if (progress - oldProgress >= 1) {
                                    oldProgress = progress;
                                    emitter.onNext(progress);
                                }

                            }
                            fos.flush();
                            //下载完成
                            call.cancel();
                        } catch (Exception e) {
                            emitter.onError(e);
                        } finally {
                            try {
                                if (is != null) {
                                    is.close();
                                }
                            } catch (IOException e) {

                            }
                            try {
                                if (fos != null) {
                                    fos.close();
                                }
                            } catch (IOException e) {

                            }
                        }
                    }
                });
            }
        });
    }


    public interface OnDownloadListener {
        /**
         * 下载成功
         */
        void onDownloadSuccess(String path);

        /**
         * 下载进度
         *
         * @param progress
         */
        void onDownloading(int progress);

        /**
         * 下载失败
         */
        void onDownloadFailed();
    }
}


